package com.tfc.glassesfree3dplayer;

import static android.hardware.Camera.CameraInfo.CAMERA_FACING_FRONT;
import static com.tfc.glassesfree3dplayer.MainActivity.classifierEye;
import static com.tfc.glassesfree3dplayer.MainActivity.classifierFace;
import static com.tfc.glassesfree3dplayer.MainActivity.videoPath;
import static com.tfc.glassesfree3dplayer.MainActivity.videoTimeString;
import static com.tfc.glassesfree3dplayer.MainActivity.videoDuration;

import static java.lang.Thread.sleep;

import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Point;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.util.Log;
import android.view.Display;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;

import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

import com.google.android.material.switchmaterial.SwitchMaterial;

import org.opencv.android.CameraBridgeViewBase;
import org.opencv.android.Utils;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfRect;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;
import org.opencv.videoio.VideoCapture;
import org.opencv.videoio.Videoio;

import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Locale;


public class PlayerActivity extends AppCompatActivity implements CameraBridgeViewBase.CvCameraViewListener2 {
    public static String TAG = "3D_Player";
    private CameraBridgeViewBase mCVCamera;
    VideoCapture videoCapture = new VideoCapture();
    private MediaPlayer mMediaPlayer;
    private ImageView imageView;
    private TextView angleNumText;
    private TextView nowFrameRate;
    private TextView nowVideoFrame;
    public TextView videoDurationNum;  //显示视频时长的组件
    //视频帧相关变量
    int frameCount = 0; // 视频总帧数
    int nowFrameNum = 0;    //当前已播放帧数
    double videoFTP = 0.0;  //视频帧率
    long startTime;
    long endTime;
    long runTime;
    long sleep_time = 30;
    double leftEyeLocationX  = 0;
    double leftEyeLocationY  = 0;
    double rightEyeLocationX  = 0;
    double rightEyeLocationY  = 0;
    double middleLocationX  = 0;
    double middleLocationY  = 0;
    double angleX = 0;
    private ImageView btnPlayPause;
    private SeekBar seekBar;
    private boolean isPlaying = false;
    private boolean videoTypeSwitchState = true;
    //Toast相关
    private static long lastToastTime = 0;
    private static final long TOAST_INTERVAL = 5000; // Toast显示间隔5秒

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EdgeToEdge.enable(this);

        //隐藏状态栏
        View decorView = getWindow().getDecorView();
        int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN;
        decorView.setSystemUiVisibility(uiOptions);

        // 设置为横屏
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        setContentView(R.layout.activity_player);

        //在开启了EdgeToEdge的情况下，防止内容与状态栏重叠
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.player_activity), (v, insets) -> {
            Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
            return insets;
        });

        //设置组件对象
        imageView = findViewById(R.id.video_view);
        mCVCamera = findViewById(R.id.camera_view);
        nowFrameRate = findViewById(R.id.now_frame_rate);
        TextView videoFrameRate = findViewById(R.id.video_frame_rate);
        nowVideoFrame = findViewById(R.id.now_video_frame);
        videoDurationNum = findViewById(R.id.video_duration_num);
        btnPlayPause = findViewById(R.id.btn_play_icon);
        angleNumText = findViewById(R.id.angle_num_text);
        seekBar = findViewById(R.id.seek_bar);
        //定义开关组件
        SwitchMaterial videoTypeToggle = findViewById(R.id.video_type_toggle);
        SwitchMaterial cameraOpenToggle = findViewById(R.id.camera_open_toggle);
        //初始化摄像头
        mCVCamera.setCameraPermissionGranted();
        mCVCamera.setCvCameraViewListener(this);
        // 设置相机方向为前置摄像头
        mCVCamera.setCameraIndex(CAMERA_FACING_FRONT);

        //显示视频时长
        Log.i(TAG, "视频时长：" + videoTimeString);
        videoDurationNum.setText(videoTimeString);

        //组件状态监听
        videoTypeToggle.setOnCheckedChangeListener((compoundButton, isToggleChecked) -> {
            if(isToggleChecked){
                videoTypeSwitchState = true;
                Toast.makeText(PlayerActivity.this, "3D视频模式", Toast.LENGTH_SHORT).show();
            }else{
                videoTypeSwitchState = false;
                Toast.makeText(PlayerActivity.this, "普通视频模式", Toast.LENGTH_SHORT).show();
            }
        });
        cameraOpenToggle.setOnCheckedChangeListener((compoundButton, isToggleChecked) -> {
            if(isToggleChecked){
                angleNumText.setVisibility(View.VISIBLE);
                mCVCamera.enableView();
                mCVCamera.setVisibility(CameraBridgeViewBase.VISIBLE);
                Toast.makeText(PlayerActivity.this, "开启摄像头", Toast.LENGTH_SHORT).show();
            }else{
                angleNumText.setVisibility(View.GONE);
                mCVCamera.disableView();
                mCVCamera.setVisibility(CameraBridgeViewBase.INVISIBLE);
                Toast.makeText(PlayerActivity.this, "关闭摄像头", Toast.LENGTH_SHORT).show();
            }
        });
        btnPlayPause.setOnClickListener(view -> isPlaying = !isPlaying);
        seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {}
            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {}
            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {}
        });

        // 初始化MediaPlayer用于音频播放
        mMediaPlayer = new MediaPlayer();
        try {
            mMediaPlayer.setDataSource(videoPath);
            mMediaPlayer.prepare();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        // 使用OpenCV的VideoCapture的open方法打开视频
        boolean opened = videoCapture.open(videoPath);
        Log.i(TAG, "视频路径：" + videoPath);
        //获取视频帧率
        videoFTP = videoCapture.get(Videoio.CAP_PROP_FPS);
        if(videoFTP == 0){
            videoFTP = 30.0;
        }
        videoFrameRate.setText("视频帧率：" + videoFTP + "FPS");

        if (opened) {
            Log.i(TAG, "视频打开成功");
            //获取视频第一帧，并显示
            Mat frame = new Mat();
            videoCapture.read(frame);
            frame = processImageAdd(frame);
            //将检测结果传给Bitmap图中
            Bitmap resultBitmap = Bitmap.createBitmap(frame.width(), frame.height(), Bitmap.Config.ARGB_8888);
            Utils.matToBitmap(frame, resultBitmap);
            imageView.setImageBitmap(resultBitmap);

            // 启动一个线程更新进度条和帧率
            new Thread(() -> {
                while (videoCapture != null && videoCapture.isOpened()) {
                    if (isPlaying) {
                        runOnUiThread(() -> {
                            //更新进度条
                            int progress = (int)((nowFrameNum / (videoDuration * videoFTP)) * 100);
                            seekBar.setProgress(progress);
                            //显示帧数
                            this.runOnUiThread(() -> nowFrameRate.setText("实时帧率：" + 1000 / runTime + "FPS"));
                            //根据帧率调整休眠时间
                            if((double) 1000 / runTime > videoFTP + 1){
                                sleep_time = sleep_time + 1;
                            }else if((double) 1000 / runTime < videoFTP){
                                if(sleep_time > 1){
                                    sleep_time = sleep_time - 1;
                                }else{
                                    //卡顿提醒，TOAST_INTERVAL时间内仅提示一次
                                    long currentTime = System.currentTimeMillis();
                                    if (currentTime - lastToastTime > TOAST_INTERVAL) {
                                        this.runOnUiThread(() -> Toast.makeText(PlayerActivity.this, "检测到视频播放卡顿！", Toast.LENGTH_SHORT).show());
                                        lastToastTime = currentTime;
                                    }
                                }
                            }
                        });
                    }
                    try {
                        sleep(200); // 更新频率
                    } catch (Exception e) {
                        Log.e(TAG, "发生错误" + e.getMessage());
                    }
                }
            }).start();

            //创建多线程，执行帧捕捉
            new Thread(() -> {
                try {
                    Mat frame1 = new Mat();
                    Mat matdst = new Mat();

                    //播放音频
                    mMediaPlayer.start();
                    //修改播放状态标识符
                    isPlaying = true;
                    btnPlayPause.setImageResource(android.R.drawable.ic_media_pause);
                    // 正在播放视频，保持屏幕常亮
                    runOnUiThread(() -> getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON));

                    while (videoCapture.read(frame1)) {
                        //暂停播放
                        if(!isPlaying){
                            btnPlayPause.setImageResource(android.R.drawable.ic_media_play);
                            mMediaPlayer.pause();
                            // 未播放视频，取消屏幕常亮，并显示提示信息
                            runOnUiThread(() -> {
                                getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
                                Toast.makeText(PlayerActivity.this, "暂停播放", Toast.LENGTH_SHORT).show();
                            });

                            while(true){
                                if(isPlaying){
                                    btnPlayPause.setImageResource(android.R.drawable.ic_media_pause);
                                    mMediaPlayer.start();
                                    // 正在播放视频，保持屏幕常亮
                                    runOnUiThread(() -> getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON));
                                    break;
                                }
                            }
                        }

                        //每1帧的起始时间
                        startTime = System.currentTimeMillis();

                        //格式化当前播放时间并显示
                        nowFrameNum = nowFrameNum + 1;
                        double nowPlayTime = (nowFrameNum/videoFTP);
                        int hours = (int) (nowPlayTime / 3600); // 计算小时数
                        int remainder = (int) (nowPlayTime % 3600); // 计算剩余秒数
                        int minutes = remainder / 60; // 计算分钟数
                        int seconds = remainder % 60; // 计算剩余秒数
                        this.runOnUiThread(() -> nowVideoFrame.setText(String.format(Locale.getDefault(), "%02d:%02d:%02d", hours, minutes, seconds)));

                        //获取当前音频和视频播放时间
                        long nowAudioPlayTime = mMediaPlayer.getCurrentPosition();
                        long nowVideoPlayTime = (long) (1000L * nowFrameNum/videoFTP);
                        // 音视频同步策略
                        double syncDiff = nowVideoPlayTime - nowAudioPlayTime; // 毫秒
                        if (Math.abs(syncDiff) > 40) {  //同步阈值40ms
                            if (syncDiff > 0) {
                                // 视频超前于音频，需要等待
                                sleep(sleep_time);
                                //重新记录起始时间
                                startTime = System.currentTimeMillis();
                            } else {
                                // 视频落后于音频，需要追赶，直接跳过这一帧
                                continue;
                            }
                        }

                        //把当前数据复制一份给matdst
                        frame1.copyTo(matdst);

                        if(videoTypeSwitchState){
                            try {
                                //图像处理
                                matdst = processImageAdd(frame1);
                            }catch (IllegalArgumentException e){
                                //图像像素不是偶像素，取消3D图像处理
                                videoTypeSwitchState = false;
                                runOnUiThread(() -> {
                                    videoTypeToggle.setActivated(false);
                                    Toast.makeText(PlayerActivity.this, "图像像素无法处理，已退出3D视频模式", Toast.LENGTH_SHORT).show();
                                });
                            }
                        }

                        //休眠以保持帧率为视频帧率
                        sleep(sleep_time);

                        //将结果传给Bitmap图中
                        Bitmap resultBitmap1 = Bitmap.createBitmap(matdst.width(), matdst.height(), Bitmap.Config.ARGB_8888);
                        Utils.matToBitmap(matdst, resultBitmap1);

                        //在主线程中更新UI
                        this.runOnUiThread(() -> imageView.setImageBitmap(resultBitmap1));

                        //每1帧的结束时间
                        endTime = System.currentTimeMillis();
                        //每1帧的时间差
                        runTime = endTime - startTime;
                    }
                    //循环结束，视频播放完毕，修改播放状态标识符，关闭屏幕常亮，显示播放结束画面
                    isPlaying = false;
                    btnPlayPause.setImageResource(android.R.drawable.ic_media_play);
                    runOnUiThread(() -> {
                        // 获取 raw 图片的输入流
                        InputStream inputStream = getResources().openRawResource(R.raw.end);
                        // 将输入流转换为 Bitmap 对象
                        Bitmap endPicture = BitmapFactory.decodeStream(inputStream);
                        imageView.setImageBitmap(endPicture);
                        getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
                    });
                } catch (Exception e) {
                    Log.i(TAG, "视频播放发生错误！" + e);
                    //发生错误，在主线程中显示提示信息
                    runOnUiThread(() -> Toast.makeText(PlayerActivity.this, "视频播放出错！"+e, Toast.LENGTH_SHORT).show());
                }
            }).start();
        }else{
            Log.i(TAG, "视频打开失败");
            Toast.makeText(this, "视频打开失败！", Toast.LENGTH_SHORT).show();
        }
    }

    //实时接收摄像头数据，然后调用classifier人眼检测，对摄像头每一帧进行处理
    @Override
    public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
        Mat frame = inputFrame.rgba();
        Mat gray = new Mat();
        Imgproc.cvtColor(frame, gray, Imgproc.COLOR_RGBA2GRAY);

        MatOfRect faceDetections = new MatOfRect();
        classifierFace.detectMultiScale(gray, faceDetections, 1.1, 3, 0, new Size(100, 100));
        if(faceDetections.empty()){
            MatOfRect eyeDetections = new MatOfRect();
            classifierEye.detectMultiScale(gray, eyeDetections, 1.1, 3, 0, new Size(20, 20));
            Rect[] eyes = eyeDetections.toArray();
            if (eyes.length == 2) {
                // 按x坐标排序
                Arrays.sort(eyes, Comparator.comparingInt(e -> e.x));

                // 左眼（蓝色）
                Rect leftEye = new Rect(eyes[0].x, eyes[0].y, eyes[0].width, eyes[0].height);
                Imgproc.rectangle(frame, leftEye.tl(), leftEye.br(), new Scalar(255, 0, 0), 2);
                Imgproc.putText(frame, "Left Eye", leftEye.tl(), Imgproc.FONT_HERSHEY_SIMPLEX, 0.5, new Scalar(255, 0, 0));
                leftEyeLocationX = (leftEye.tl().x+leftEye.br().x)/2;
                leftEyeLocationY = (leftEye.tl().y+leftEye.br().y)/2;
                // 右眼（红色）
                Rect rightEye = new Rect(eyes[1].x, eyes[1].y, eyes[1].width, eyes[1].height);
                Imgproc.rectangle(frame, rightEye.tl(), rightEye.br(), new Scalar(0, 0, 255), 2);
                Imgproc.putText(frame, "Right Eye", rightEye.tl(), Imgproc.FONT_HERSHEY_SIMPLEX, 0.5, new Scalar(0, 0, 255));
                rightEyeLocationX = (rightEye.tl().x+rightEye.br().x)/2;
                rightEyeLocationY = (rightEye.tl().y+rightEye.br().y)/2;

                middleLocationX = (leftEyeLocationX + rightEyeLocationX)/2;
                middleLocationY = (leftEyeLocationY + rightEyeLocationY)/2;

                angleX  = Math.abs((middleLocationX - (double) frame.width() /2))/((double) frame.width());
                angleNumText.setText(String.format(Locale.CHINA, "%.2f", angleX));
            }else if (eyes.length == 1) {
                // 单眼（绿色）
                Rect eye = new Rect(eyes[0].x, eyes[0].y, eyes[0].width, eyes[0].height);
                Imgproc.rectangle(frame, eye.tl(), eye.br(), new Scalar(0, 255, 0), 2);
                Imgproc.putText(frame, "Eye", eye.tl(), Imgproc.FONT_HERSHEY_SIMPLEX, 0.5, new Scalar(0, 255, 0));
                angleX  = Math.abs(((eye.tl().x+eye.br().x)/2 - (double) frame.width() /2))/((double) frame.width());
                angleNumText.setText(String.format(Locale.CHINA, "%.2f", angleX));
            }
        }else{
            for (Rect faceRect : faceDetections.toArray()) {
                // 在人脸区域内检测眼睛
                Mat faceROI = gray.submat(faceRect);
                MatOfRect eyeDetections = new MatOfRect();
                classifierEye.detectMultiScale(faceROI, eyeDetections, 1.1, 3, 0, new Size(20, 20));

                Rect[] eyes = eyeDetections.toArray();
                if (eyes.length == 2) {
                    // 按x坐标排序
                    Arrays.sort(eyes, Comparator.comparingInt(e -> e.x));

                    // 左眼（蓝色）
                    Rect leftEye = new Rect(faceRect.x + eyes[0].x, faceRect.y + eyes[0].y, eyes[0].width, eyes[0].height);
                    Imgproc.rectangle(frame, leftEye.tl(), leftEye.br(), new Scalar(255, 0, 0), 2);
                    Imgproc.putText(frame, "Left Eye", leftEye.tl(), Imgproc.FONT_HERSHEY_SIMPLEX, 0.5, new Scalar(255, 0, 0));
                    leftEyeLocationX = (leftEye.tl().x+leftEye.br().x)/2;
                    leftEyeLocationY = (leftEye.tl().y+leftEye.br().y)/2;
                    // 右眼（红色）
                    Rect rightEye = new Rect(faceRect.x + eyes[1].x, faceRect.y + eyes[1].y, eyes[1].width, eyes[1].height);
                    Imgproc.rectangle(frame, rightEye.tl(), rightEye.br(), new Scalar(0, 0, 255), 2);
                    Imgproc.putText(frame, "Right Eye", rightEye.tl(), Imgproc.FONT_HERSHEY_SIMPLEX, 0.5, new Scalar(0, 0, 255));
                    rightEyeLocationX = (rightEye.tl().x+rightEye.br().x)/2;
                    rightEyeLocationY = (rightEye.tl().y+rightEye.br().y)/2;

                    middleLocationX = (leftEyeLocationX + rightEyeLocationX)/2;
                    middleLocationY = (leftEyeLocationY + rightEyeLocationY)/2;

                    angleX  = Math.abs((middleLocationX - (double) frame.width() /2))/((double) frame.width());
                    angleNumText.setText(String.format(Locale.CHINA, "%.2f", angleX));
                }else if (eyes.length == 1) {
                    // 单眼（绿色）
                    Rect eye = new Rect(faceRect.x + eyes[0].x, faceRect.y + eyes[0].y, eyes[0].width, eyes[0].height);
                    Imgproc.rectangle(frame, eye.tl(), eye.br(), new Scalar(0, 255, 0), 2);
                    Imgproc.putText(frame, "Eye", eye.tl(), Imgproc.FONT_HERSHEY_SIMPLEX, 0.5, new Scalar(0, 255, 0));
                    angleX  = Math.abs(((eye.tl().x+eye.br().x)/2 - (double) frame.width() /2))/((double) frame.width());
                    angleNumText.setText(String.format(Locale.CHINA, "%.2f", angleX));
                }
            }
        }

        return frame;
    }

    //处理图像
    public Mat processImageAdd(Mat frame){
        // 确保图片宽度是偶数
        if (frame.width() % 2 != 0) {
            throw new IllegalArgumentException("Side-by-side image width must be even");
        }

        int halfWidth = frame.width() / 2;

        // 定义左右眼的ROI区域
        Mat leftEye = new Mat(frame, new Rect(0, 0, halfWidth, frame.height()));
        Mat rightEye = new Mat(frame, new Rect(halfWidth, 0, halfWidth, frame.height()));

        // 确保两张图像大小相同
        if (leftEye.size().equals(rightEye.size())) {
            Mat result = new Mat();
            // 混合图像 - 这里使用0.5和0.5的权重，gamma为0
            Core.addWeighted(leftEye, Math.abs(0.5-angleX), rightEye, 1 - Math.abs(0.5-angleX), 0, result);
            return result;
        }
        return frame;
    }

    @Override
    public void onCameraViewStarted(int width, int height) {
        // 计算合适的预览比例
        Display display = getWindowManager().getDefaultDisplay();
        Point size = new Point();
        display.getSize(size);
        int screenWidth = size.x;
        int screenHeight = size.y;

        float previewRatio = (float) width / height;
        float screenRatio = (float) screenWidth / screenHeight;

        if (screenRatio > previewRatio) {
            // 横向黑边
            int newWidth = (int) (screenHeight * previewRatio);
            mCVCamera.getLayoutParams().width = newWidth/4;
            mCVCamera.getLayoutParams().height = screenHeight/4;
        } else {
            // 纵向黑边
            int newHeight = (int) (screenWidth / previewRatio);
            mCVCamera.getLayoutParams().width = screenWidth/4;
            mCVCamera.getLayoutParams().height = newHeight/4;
        }

        mCVCamera.requestLayout();
    }

    @Override
    public void onCameraViewStopped() {
    }

    @Override
    protected void onResume() {
        super.onResume();
        mCVCamera.enableView();
        mMediaPlayer.start();

    }

    @Override
    protected void onPause() {
        super.onPause();
        mCVCamera.disableView();
        mMediaPlayer.pause();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mCVCamera.disableView();
        mMediaPlayer.release();
        videoCapture.release();
    }
}